#include "display.h"
#include "string.h"

AWRender::AWRender():IVidRender(),
                    _isStarted(false),
                    _width(0),
                    _height(0),
                    _ratio_height(0),
                    _disp_inst(NULL),
                    _image_yuv_inst(NULL),
                    _image_rgb_inst(NULL),
                    _image_disp_inst(NULL){
    libmaix_image_module_init();
}

AWRender::~AWRender(){
    libmaix_image_module_deinit();
}

int32_t AWRender::Start( int32_t id, int32_t w, int32_t h ){

    if( _isStarted == true ){
        Stop();
    }

    _width = w;
    _height = h;

    _disp_inst = libmaix_disp_creat();
    if( _disp_inst == NULL ){
        printf( "create_display failed\r\n" );
        return -1;
    }

    float ratio = ((float)_width)/((float)_height);
    _ratio_height = ((float)_disp_inst->height)/ratio;


    _image_yuv_inst = libmaix_image_create( w, h,
                                            LIBMAIX_IMAGE_MODE_YUV420SP_NV21,
                                            LIBMAIX_IMAGE_LAYOUT_HWC,
                                            NULL,
                                            false );
    if( _image_yuv_inst == NULL ){
        printf( "create _image_yuv_inst failed\r\n" );
        return -1;
    }


    _image_rgb_inst = libmaix_image_create( w, h,
                                            LIBMAIX_IMAGE_MODE_RGB888,
                                            LIBMAIX_IMAGE_LAYOUT_HWC,
                                            NULL,
                                            true );
    if( _image_rgb_inst == NULL ){
        printf( "create _image_rgb_inst failed\r\n" );
        return -1;
    }


    _image_disp_inst = libmaix_image_create( _disp_inst->width, _ratio_height,
                                            LIBMAIX_IMAGE_MODE_RGB888,
                                            LIBMAIX_IMAGE_LAYOUT_HWC,
                                            NULL,
                                            true );
    if( _image_disp_inst == NULL ){
        printf( "create _image_rgb_inst failed\r\n" );
        return -1;
    }


    _isStarted = true;
    return 0;
}

int32_t AWRender::Deliver(struct MemoryFrame *frame){

    int32_t ret = -1;
    if( frame == NULL ){
        printf( "error param....\r\n" );
        return -1;
    }

    if( _isStarted == false ){
        printf( "no start....\r\n" );
        return -1;
    }

    frame->ops.add_ref(frame->frame);

    _image_yuv_inst->mode = LIBMAIX_IMAGE_MODE_YUV420SP_NV21;
    _image_yuv_inst->data = (void*)frame->addr;
    ret = _image_yuv_inst->convert( _image_yuv_inst,
                              LIBMAIX_IMAGE_MODE_RGB888,
                              &_image_rgb_inst );
    if( ret < 0 ){
        printf( "%s convert image failed:%d....\r\n", __FUNCTION__, ret );
        return -1;
    }

    ret = _image_rgb_inst->resize( _image_rgb_inst,
                             _image_disp_inst->width,
                             _image_disp_inst->height,
                             &_image_disp_inst );
    if( ret < 0 ){
        printf( "%s resize image failed:%d....\r\n", __FUNCTION__,ret );
        return -1;
    }

    ret = _disp_inst->draw( _disp_inst,
                      (unsigned char*)_image_disp_inst->data,
                      (_disp_inst->width - _image_disp_inst->width) / 2,
                      0,
                      _image_disp_inst->width,
                      _image_disp_inst->height,
                      1 );

    if( ret < 0 ){
        printf( "%s draw image failed:%d....\r\n", __FUNCTION__, ret );
        return -1;
    }

    frame->ops.dec_ref(frame->frame);

    return 0;
}


int32_t AWRender::Stop(){

    if( _isStarted == false ){
        printf( "no start....\r\n" );
        return -1;
    }

    if( _disp_inst != NULL ){
        libmaix_disp_destroy(&_disp_inst);
        _disp_inst = NULL;
    }

    if( _image_yuv_inst != NULL ){
        libmaix_image_destroy(&_image_yuv_inst);
        _image_yuv_inst = NULL;
    }

    if( _image_rgb_inst != NULL ){
        libmaix_image_destroy(&_image_rgb_inst);
        _image_rgb_inst = NULL;
    }

    if( _image_disp_inst != NULL ){
        libmaix_image_destroy(&_image_disp_inst);
        _image_disp_inst = NULL;
    }

    _isStarted = false;

    return 0;
}



int32_t aw_vid_render_init( int32_t width, int32_t height, /*out*/AW_VID_RENDER_HANDLE *handle ){
    vid_render_ins *ins = new vid_render_ins();
    ins->width = width;
    ins->height = height;
    ins->IVidRend = new AWRender();
    printf( "IVidRend:%p\r\n", ins->IVidRend );
    if( ins->IVidRend == NULL ){
        return -1;
        printf( "get_instance failed...............\r\n" );
    }
    *handle = (AW_VID_RENDER_HANDLE)ins;
    return 0;
}

int32_t aw_vid_render_deinit( /*in*/AW_VID_RENDER_HANDLE handle ){

    int32_t ret = 0;
    vid_render_ins *ins = (vid_render_ins*)handle;
    if( ins == NULL || ins->IVidRend == NULL ){
        printf( "%s param Error....\r\n", __FUNCTION__ );
        return -1;
    }
    delete ins->IVidRend;
    delete ins;
    return ret;
}

int32_t aw_vid_render_start( /*in*/AW_VID_RENDER_HANDLE handle ){

    int32_t ret = 0;
    vid_render_ins *ins = (vid_render_ins*)handle;
    printf( "IVidRend:%p\r\n", ins->IVidRend );
    if( ins == NULL || ins->IVidRend == NULL ){
        printf( "%s param Error.................\r\n", __FUNCTION__ );
        return -1;
    }
    ret = ins->IVidRend->Start(0, ins->width, ins->height);
    if( ret < 0 ){
        printf( "aw_vid_render_start failed\r\n" );
        return -1;
    }
    return ret;

}
int32_t aw_vid_render_stop( /*in*/AW_VID_RENDER_HANDLE handle ){
    int32_t ret = 0;
    vid_render_ins *ins = (vid_render_ins*)handle;
    if( ins == NULL || ins->IVidRend == NULL ){
        printf( "%s param Error....\r\n", __FUNCTION__ );
        return -1;
    }
    ret = ins->IVidRend->Stop();
    if( ret < 0 ){
        printf( "aw_vid_render_stop failed\r\n" );
        return -1;
    }
    return ret;


}

int32_t aw_vid_render_deliver( /*in*/AW_VID_RENDER_HANDLE handle, struct MemoryFrame *frame ){
    int32_t ret = 0;
    vid_render_ins *ins = (vid_render_ins*)handle;
    if( ins == NULL || ins->IVidRend == NULL ){
        printf( "%s param Error....\r\n", __FUNCTION__ );
        return -1;
    }
    ret = ins->IVidRend->Deliver(frame);
    if( ret < 0 ){
        printf( "aw_vid_render_deliver failed\r\n" );
        return -1;
    }
    return ret;
}
